package com.beesphere.products.throttling.tests;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beesphere.products.throttling.AsyncCallback;
import com.beesphere.products.throttling.UnitOfWork;
import com.beesphere.products.throttling.executor.PoolConfiguration;
import com.beesphere.products.throttling.executor.impl.DefaultExecutorServiceFactory;
import com.beesphere.products.throttling.impl.DefaultUnitOfWorkCapacity;
import com.beesphere.products.throttling.impl.PoolBasedThrottler;

public abstract class AbstractThrottlingTest {
	
	private static final Logger logger = LoggerFactory.getLogger (AbstractThrottlingTest.class);
	
	public void startTest () throws Exception {
		startTest (0);
	}
	public void startTest (long timeout) throws Exception {
		startTest (timeout, PoolConfiguration.THREAD_STACK_SIZE);
	}
	public void startTest (long timeout, long stackSize) throws Exception {
		// this has to be called one time, ex. in your server startup
		DefaultUnitOfWorkCapacity capacity = 
			new DefaultUnitOfWorkCapacity ("UnRegisteredUsers", "u501");
		capacity.setTimeout (timeout);
		if (stackSize > 0) {
			capacity.setStackSize(stackSize);
		}
		PoolBasedThrottler t = 
			new PoolBasedThrottler (
				new DefaultExecutorServiceFactory (),
				capacity
			);
		
		t.start ();

		// a new coming request to proceed
		final UnitOfWork uow = createUnitOfWork ();
		t.process (
			uow, 
			new AsyncCallback () {
				private static final long serialVersionUID = -1921967193427132838L;
				private final Logger logger = LoggerFactory.getLogger (AsyncCallback.class);
				@Override
				public void done (Object unitOfWorkResult, boolean doneSynchronously) {
					if (uow.isCanceled ()) {
						logger.error ("Unit Of Work Timeout - " + uow.getError ());
						return;
					}
					logger.debug ("Async :" + !doneSynchronously);
					logger.debug ("Result:" + unitOfWorkResult);
					if (uow.getError () != null) {
						logger.error ("" + uow.getError ());
					}
				}
			}
		);
		afterProcess (uow);
		uow.release ();
		t.stop ();
	}

	protected void afterProcess (UnitOfWork uow) {
		logger.debug ("Ending [" + this.getClass () + "]");
	}

	protected abstract UnitOfWork createUnitOfWork ();
	
}
